package org.adream.account.util;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import org.springframework.core.io.support.ResourcePropertySource;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

public class WeixinUtil {
	private static Logger logger = Logger.getLogger(WeixinUtil.class);

	private static Map<String,Token> tokenMap = new HashMap<String,Token>();
	
	//当前测试appid
	public static final String WXAPP_APPID;
	public static final String WXAPP_SECRET;
	
	static {
		try {
			logger.info("正在读取info配置文件");
			ResourcePropertySource rps = new ResourcePropertySource("classpath:/config/info.properties");
			WXAPP_APPID = String.valueOf(rps.getProperty("wxapp.appid"));
			WXAPP_SECRET = String.valueOf(rps.getProperty("wxapp.secret"));
			logger.info("appid:" + WXAPP_APPID);
		} catch (IOException e) {
			throw new Error("无法读取sms。properties",e);
		}
	}
	
	// 传入URL
	public synchronized static String getAccess_token(String url) throws Exception {
		logger.debug("***getAccess_token***");
		Token token = tokenMap.get(url);
		if(token != null && new Date().before(token.expireDate)){
			logger.debug("token未过期，从缓存中获取token："+token.accessToken+",过期时间:");
			logger.debug(token.expireDate);
			return token.accessToken;
		}
		logger.debug("token过期");
		String accessToken = null;
		try {
			URL urlGet = new URL(url);
			HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
			http.setRequestMethod("GET"); // 必须是get方式请求
			http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
			http.setDoOutput(true);
			http.setDoInput(true);
			System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒
			System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒
			http.connect();
			InputStream is = http.getInputStream();
			int size = is.available();
			byte[] jsonBytes = new byte[size];
			is.read(jsonBytes);
			accessToken = new String(jsonBytes, "UTF-8");
			is.close();
		} catch (Exception e) {
			logger.error(e.getMessage(),e);
			return null;
		}
		
		JSONObject map = JSON.parseObject(accessToken);
		logger.debug("map:"+map.toJSONString());
		int rltCode = map.getIntValue("errcode");
		if(rltCode != 0){
			logger.error("******获取accessToken失败*******");
			logger.error(accessToken);
			throw new Exception("获取accessToken失败");
		}
		Token tokenNew = new Token();
		tokenNew.accessToken = (String)map.get("access_token");
		tokenNew.expireDate = new Date(new Date().getTime() + map.getIntValue("expires_in")*1000 - 30000);//提早30秒过期防止误差
		tokenMap.put(url, tokenNew);
		logger.debug("返回token:"+tokenNew.accessToken);
		return tokenNew.accessToken;
	}
	
	// 传入URL
	public synchronized static Token getToken(String url) throws Exception {
		logger.debug("***get token***");
		Token token = tokenMap.get(url);
		if (token != null && new Date().before(token.expireDate)) {
			logger.debug("token未过期，从缓存中获取token：" + token.accessToken + ",过期时间:");
			logger.debug(token.expireDate);
			return token;
		}
		logger.debug("token过期");
		String accessToken = null;
		try {
			URL urlGet = new URL(url);
			HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
			http.setRequestMethod("GET"); // 必须是get方式请求
			http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
			http.setDoOutput(true);
			http.setDoInput(true);
			System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒
			System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒
			http.connect();
			InputStream is = http.getInputStream();
			int size = is.available();
			byte[] jsonBytes = new byte[size];
			is.read(jsonBytes);
			accessToken = new String(jsonBytes, "UTF-8");
			is.close();
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			return null;
		}

		JSONObject map = JSON.parseObject(accessToken);
		logger.debug("map:" + map.toJSONString());
		int rltCode = map.getIntValue("errcode");
		if (rltCode != 0) {
			logger.error("******获取accessToken失败*******");
			logger.error(accessToken);
			throw new Exception("获取accessToken失败");
		}
		Token tokenNew = new Token();
		tokenNew.accessToken = (String) map.get("access_token");
		tokenNew.unionid = (String) map.get("unionid");
		tokenNew.openId = (String) map.get("openid");
		tokenNew.expireDate = new Date(new Date().getTime() + map.getIntValue("expires_in") * 1000 - 30000);// 提早30秒过期防止误差
		tokenMap.put(url, tokenNew);
		return tokenNew;
	}
	
	
	/**
	 * 登陆回调获取accessToken
	 * @param code
	 * @return
	 */
	public static String getAccessToken(String code) {
		String accessToken = null;
		try {
			String tokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
			String url = String.format(tokenUrl, WXAPP_APPID,WXAPP_SECRET,code);
			URL urlGet = new URL(url);
			HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
			http.setRequestMethod("GET"); //
			http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
			http.setDoOutput(true);
			http.setDoInput(true);
			System.setProperty("sun.net.client.defaultConnectTimeout", "30000");//
			System.setProperty("sun.net.client.defaultReadTimeout", "30000"); //
			http.connect();
			InputStream is = http.getInputStream();
			int size = is.available();
			byte[] jsonBytes = new byte[size];
			is.read(jsonBytes);
			accessToken = new String(jsonBytes, "UTF-8");
			is.close();
		} catch (Exception e) {
			logger.error(e.getMessage(),e);
			return null;
		}

		return accessToken;
	}
	
	
	public static class Token{
		//接口调用凭证
		private String accessToken;
		
		//当且仅当该网站应用已获得该用户的userinfo授权时,才会出现该字段
		private String unionid;
		
		//授权用户唯一标识
		private String openId;
		
		//access_token接口调用凭证超时时间,单位(秒)
		private Date expireDate;
		
		public String getAccessToken() {
			return accessToken;
		}
		
		public void setAccessToken(String accessToken) {
			this.accessToken = accessToken;
		}
		
		public String getUnionid() {
			return unionid;
		}
		
		public void setUnionid(String unionid) {
			this.unionid = unionid;
		}
		
		public String getOpenId() {
			return openId;
		}
		
		public void setOpenId(String openId) {
			this.openId = openId;
		}
		
		public Date getExpireDate() {
			return expireDate;
		}
		
		public void setExpireDate(Date expireDate) {
			this.expireDate = expireDate;
		}
	}
}